﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using BaseAPI.BaseModel;
using BaseAPI.BaseViewModel;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Snowflake.Core;

namespace BaseAPI.BaseController;

public abstract class BaseController<T> : ControllerBase where T : BaseEntity, new()
{
    protected readonly DbContext Context;
    protected readonly ModelServer<T> ModelServer;
    protected readonly ControllerServer<T> ControllerServer;
    protected readonly IMapper Mapper;
    protected readonly IdWorker IDWorker;

    protected BaseController(DbContext context, IMapper mapper, IdWorker idWorker)
    {
        Context = context;
        ModelServer = new ModelServer<T>(context);
        ControllerServer = new ControllerServer<T>(ModelServer);
        Mapper = mapper;
        IDWorker = idWorker;
    }

    #region 新增

    /// <summary>
    /// 添加单个实体
    /// </summary>
    /// <param name="baseCreateViewModel">实体视图类</param>
    /// <returns></returns>
    protected async Task<ResponseModel<string>> Z_Create(BaseCreateViewModel<T> baseCreateViewModel)
    {
        T t;
        try
        {
            t = baseCreateViewModel.CreateModel(Mapper, IDWorker);
        }
        catch (Exception e)
        {
            return ResponseModel<string>.HandleError(e);
        }

        return await ControllerServer.Add(t);
    }

    /// <summary>
    /// 添加多个实体
    /// </summary>
    /// <param name="baseCreateViewModels">实体视图类集合</param>
    /// <returns></returns>
    protected async Task<ResponseModel<List<string>>> Z_Create(IEnumerable<BaseCreateViewModel<T>> baseCreateViewModels)
    {
        List<T> tl;
        try
        {
            tl = baseCreateViewModels.Select(x => x.CreateModel(Mapper, IDWorker)).ToList();
        }
        catch (Exception e)
        {
            return ResponseModel<List<string>>.HandleError(e);
        }

        return await ControllerServer.Add(tl);
    }

    #endregion

    #region 查询

    protected async Task<ResponseModel<List<T>>> Z_GetList(BaseGetListViewModel<T> baseGetListViewModel)
    {
        return await ControllerServer.GetList(baseGetListViewModel.QueryFun, baseGetListViewModel.PageRequest);
    }

    protected async Task<ResponseModel<List<TU>>> Z_GetList<TU>(BaseGetListViewModel<T, TU> baseGetListViewModel)
    {
        baseGetListViewModel.Init(Mapper, Context);
        return await ControllerServer.GetList(baseGetListViewModel.TransFun, baseGetListViewModel.PageRequest);
    }

    protected async Task<ResponseModel<T>> Z_GetOne(long id)
    {
        return await ControllerServer.GetOne(id);
    }

    protected async Task<ResponseModel<T>> Z_GetOne(BaseGetOneViewModel<T> baseGetOneViewModel)
    {
        return await ControllerServer.GetOne(baseGetOneViewModel.QueryFun);
    }

    protected async Task<ResponseModel<TU>> Z_GetOne<TU>(long id)
    {
        var baseGetOneViewModel = new BaseGetOneViewModel<T, TU>();
        baseGetOneViewModel.Init(Mapper, Context);
        return await ControllerServer.GetOne(id, baseGetOneViewModel.TransFun);
    }

    protected async Task<ResponseModel<TU>> Z_GetOne<TU>(BaseGetOneViewModel<T, TU> baseGetOneViewModel)
    {
        baseGetOneViewModel.Init(Mapper, Context);
        if (baseGetOneViewModel.DoNotUseID)
            return await ControllerServer.GetOne(baseGetOneViewModel.TransFun);
        else
            return await ControllerServer.GetOne(baseGetOneViewModel.ID, baseGetOneViewModel.TransFun);
    }

    #endregion

    #region 修改

    /// <summary>
    /// 修改，以put的方式修改
    /// </summary>
    /// <returns></returns>
    protected async Task<ResponseModel<int>> Z_Modify(T t)
    {
        return await ControllerServer.Modify(t);
    }

    /// <summary>
    /// 修改，以patch的方式批量修改
    /// </summary>
    /// <param name="basePatchViewModel"></param>
    /// <returns></returns>
    protected async Task<ResponseModel<int>> Z_Modify(BasePatchViewModel<T> basePatchViewModel)
    {
        basePatchViewModel.Init(Mapper);
        return await ControllerServer.Modify(basePatchViewModel.GetT(), basePatchViewModel.PatchFun);
    }

    /// <summary>
    /// 批量修改，以put的方式修改
    /// </summary>
    /// <returns></returns>
    protected async Task<ResponseModel<int>> Z_Modify(IEnumerable<T> listT)
    {
        return await ControllerServer.Modify(listT.Select(x => new PatchModel<T> { Model = x }).ToList());
    }

    /// <summary>
    /// 批量修改，以patch的方式修改
    /// </summary>
    /// <param name="basePatchViewModelsArg"></param>
    /// <returns></returns>
    protected async Task<ResponseModel<int>> Z_Modify(IEnumerable<BasePatchViewModel<T>> basePatchViewModelsArg)
    {
        var basePatchViewModels = basePatchViewModelsArg.ToList();
        if (basePatchViewModels.Count == 0) return ResponseModel<int>.Success(0);
        basePatchViewModels.ForEach(x => x.Init(Mapper));
        var listModels = basePatchViewModels.Select(x => new PatchModel<T> { Model = x.GetT(), PatchFun = x.PatchFun })
            .ToList();
        return await ControllerServer.Modify(listModels);
    }

    #endregion

    #region 删除

    /// <summary>
    /// 删除单个实体
    /// </summary>
    /// <param name="id">实体ID</param>
    /// <returns></returns>
    protected async Task<ResponseModel<int>> Z_Delete(long id)
    {
        return await ControllerServer.Remove(id);
    }

    /// <summary>
    /// 删除多个实体
    /// </summary>
    /// <param name="ids">实体ID集合</param>
    /// <returns></returns>
    protected async Task<ResponseModel<int>> Z_Delete(List<long> ids)
    {
        return await ControllerServer.Remove(ids);
    }

    #endregion

    /// <summary>
    /// 获取用户ID，注意只能在需要权限的接口上使用
    /// </summary>
    /// <returns></returns>
    protected async Task<long> GetUserID()
    {
        var authenticate = await HttpContext.AuthenticateAsync();
        var auth = authenticate.Principal?.Claims;
        if (auth == null) return 0;
        var id = auth.FirstOrDefault(t => t.Type == "name")!.Value;
        return Convert.ToInt64(id);
    }

    /// <summary>
    /// 获取附件，使用流式读取，避免爆内存
    /// </summary>
    /// <param name="id">数据ID</param>
    /// <param name="table">数据所在表名称</param>
    /// <param name="field">附件字段名称</param>
    /// <param name="contentType">数据的mineType类型，默认值为application/octet-stream</param>
    /// <returns></returns>
    protected async Task<IActionResult> GetAnnex(string id, string table, string field,
        string contentType = "application/octet-stream")
    {
        // 获取底层的数据库连接
        var connection = Context.Database.GetDbConnection();
        try
        {
            if (connection.State != ConnectionState.Open)
                await connection.OpenAsync();
            await using var command = connection.CreateCommand();
            command.CommandText = $"SELECT {field} FROM {table} WHERE Id = @id";
            var parameter = command.CreateParameter();
            parameter.ParameterName = "@id";
            parameter.Value = id;
            command.Parameters.Add(parameter);
            // 使用SequentialAccess以流式方式读取数据
            await using var reader =
                await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess | CommandBehavior.CloseConnection);
            if (await reader.ReadAsync())
            {
                var blobColumnIndex = reader.GetOrdinal(field);
                // 检查数据所在列是否为DBNull
                if (reader.IsDBNull(blobColumnIndex))
                {
                    return NotFound();
                }

                // 设置Response的内容类型
                Response.ContentType = contentType;
                // 创建一个缓冲区用于分块读取数据
                var buffer = new byte[4096];
                long offset = 0;
                // 开始流式读取并直接写入到Response.Body
                await using (var stream = Response.Body)
                {
                    long bytesRead;
                    while ((bytesRead = reader.GetBytes(blobColumnIndex, offset, buffer, 0, buffer.Length)) > 0)
                    {
                        await stream.WriteAsync(buffer.AsMemory(0, (int)bytesRead));
                        offset += bytesRead;
                    }
                }

                // 返回空结果，因为已经通过Response.Body发送了数据
                return new EmptyResult();
            }
            else
            {
                return NotFound();
            }
        }
        catch (Exception e)
        {
            return StatusCode(500, e.Message);
        }
        finally
        {
            // 确保连接关闭
            if (connection.State == ConnectionState.Open)
                await connection.CloseAsync();
        }
    }
}